{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using a single Table vs EArray + Table"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The PyTables community keep asking what can be considered a FAQ.  Namely, should I use a single Table for storing my data, or should I split it in a Table and an Array?\n",
    "\n",
    "Although there is not a totally general answer, the study below address this for the common case where one has 'raw data' and other data that can be considered 'meta'.  See for example: https://groups.google.com/forum/#!topic/pytables-users/vBEiaRzp3gI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n",
      "PyTables version:    3.2.4.dev0\n",
      "HDF5 version:        1.8.16\n",
      "NumPy version:       1.11.0\n",
      "Numexpr version:     2.4.3 (not using Intel's VML/MKL)\n",
      "Zlib version:        1.2.8 (in Python interpreter)\n",
      "Blosc version:       1.9.2 (2016-06-08)\n",
      "Blosc compressors:   blosclz (1.0.5), lz4 (1.7.2), lz4hc (1.7.2), snappy (1.1.1), zlib (1.2.8)\n",
      "Blosc filters:       shuffle, bitshuffle\n",
      "Cython version:      0.23.4\n",
      "Python version:      2.7.12 (default, Jul  1 2016, 15:12:24) \n",
      "[GCC 5.4.0 20160609]\n",
      "Platform:            Linux-4.6.4-gentoo-x86_64-with-Ubuntu-16.04-xenial\n",
      "Byte-ordering:       little\n",
      "Detected cores:      8\n",
      "Default encoding:    ascii\n",
      "Default FS encoding: UTF-8\n",
      "Default locale:      (en_US, UTF-8)\n",
      "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import tables\n",
    "\n",
    "tables.print_versions()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 157,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "LEN_PMT = int(1.2e6)\n",
    "NPMTS = 12\n",
    "NEVENTS = 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!rm PMT*.h5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def gaussian(x, mu, sig):\n",
    "    return np.exp(-np.power(x - mu, 2.0) / (2 * np.power(sig, 2.0)))\n",
    "\n",
    "\n",
    "x = np.linspace(0, 1, 1e7)\n",
    "rd = (gaussian(x, 1, 1.0) * 1e6).astype(np.int32)\n",
    "\n",
    "\n",
    "def raw_data(length):\n",
    "    # Return the actual data that you think it represents PM waveforms better\n",
    "    # return np.arange(length, dtype=np.int32)\n",
    "    return rd[:length]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using Tables to store everything"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class PMTRD(tables.IsDescription):\n",
    "    # event_id = tables.Int32Col(pos=1, indexed=True)\n",
    "    event_id = tables.Int32Col(pos=1)\n",
    "    npmt = tables.Int8Col(pos=2)\n",
    "    pmtrd = tables.Int32Col(shape=LEN_PMT, pos=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def one_table(filename, filters):\n",
    "    with tables.open_file(\n",
    "        \"{}-{}-{}.h5\".format(filename, filters.complib, filters.complevel),\n",
    "        \"w\",\n",
    "        filters=filters,\n",
    "    ) as h5t:\n",
    "        pmt = h5t.create_table(\n",
    "            h5t.root, \"pmt\", PMTRD, expectedrows=NEVENTS * NPMTS\n",
    "        )\n",
    "        pmtr = pmt.row\n",
    "        for i in range(NEVENTS):\n",
    "            for j in range(NPMTS):\n",
    "                pmtr[\"event_id\"] = i\n",
    "                pmtr[\"npmt\"] = j\n",
    "                pmtr[\"pmtrd\"] = raw_data(LEN_PMT)\n",
    "                pmtr.append()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 220 ms, sys: 104 ms, total: 324 ms\n",
      "Wall time: 323 ms\n"
     ]
    }
   ],
   "source": [
    "# Using no compression\n",
    "%time one_table(\"PMTs\", tables.Filters(complib=\"zlib\", complevel=0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 3.16 s, sys: 16 ms, total: 3.17 s\n",
      "Wall time: 3.17 s\n"
     ]
    }
   ],
   "source": [
    "# Using Zlib (level 5) compression\n",
    "%time one_table(\"PMTs\", tables.Filters(complib=\"zlib\", complevel=5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 596 ms, sys: 4 ms, total: 600 ms\n",
      "Wall time: 599 ms\n"
     ]
    }
   ],
   "source": [
    "# Using Blosc (level 9) compression\n",
    "%time one_table(\"PMTs\", tables.Filters(complib=\"blosc:lz4\", complevel=9))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 42M PMTs-blosc:lz4-9.h5  550M PMTs-None-0.h5   17M PMTs-zlib-5.h5\r\n"
     ]
    }
   ],
   "source": [
    "ls -sh *.h5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So, using no compression leads to best speed, whereas Zlib can compress data by ~32x.  Zlib is ~3x slower than using no compression though.  On its hand, the Blosc compressor is faster but it can barely compress the dataset."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using EArrays for storing raw data and Table for other metadata"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 166,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def rawdata_earray(filename, filters):\n",
    "    with tables.open_file(\n",
    "        \"{}-{}.h5\".format(filename, filters.complib), \"w\", filters=filters\n",
    "    ) as h5a:\n",
    "        pmtrd = h5a.create_earray(\n",
    "            h5a.root,\n",
    "            \"pmtrd\",\n",
    "            tables.Int32Atom(),\n",
    "            shape=(0, NPMTS, LEN_PMT),\n",
    "            chunkshape=(1, 1, LEN_PMT),\n",
    "        )\n",
    "        for i in range(NEVENTS):\n",
    "            rdata = []\n",
    "            for j in range(NPMTS):\n",
    "                rdata.append(raw_data(LEN_PMT))\n",
    "            pmtrd.append(np.array(rdata).reshape(1, NPMTS, LEN_PMT))\n",
    "        pmtrd.flush()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 120 ms, sys: 132 ms, total: 252 ms\n",
      "Wall time: 250 ms\n"
     ]
    }
   ],
   "source": [
    "# Using no compression\n",
    "%time rawdata_earray(\"PMTAs\", tables.Filters(complib=\"zlib\", complevel=0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 168,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 2.72 s, sys: 24 ms, total: 2.74 s\n",
      "Wall time: 2.74 s\n"
     ]
    }
   ],
   "source": [
    "# Using Zlib (level 5) compression\n",
    "%time rawdata_earray(\"PMTAs\", tables.Filters(complib=\"zlib\", complevel=5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 169,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 224 ms, sys: 36 ms, total: 260 ms\n",
      "Wall time: 258 ms\n"
     ]
    }
   ],
   "source": [
    "# Using Blosc (level 5) compression\n",
    "%time rawdata_earray(\"PMTAs\", tables.Filters(complib=\"blosc:lz4\", complevel=9))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 170,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.0M PMTAs-blosc:lz4.h5  4.1M PMTAs-zlib.h5\t   550M PMTs-None-0.h5\r\n",
      "550M PMTAs-None.h5\t  42M PMTs-blosc:lz4-9.h5   17M PMTs-zlib-5.h5\r\n"
     ]
    }
   ],
   "source": [
    "!ls -sh *.h5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "We see that by using the Blosc compressor one can achieve around 10x faster output operation wrt Zlib, although the compression ratio can be somewhat smaller (but still pretty good)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 171,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Add the event IDs in a separate table in the same file\n",
    "class PMTRD(tables.IsDescription):\n",
    "    # event_id = tables.Int32Col(pos=1, indexed=True)\n",
    "    event_id = tables.Int32Col(pos=1)\n",
    "    npmt = tables.Int8Col(pos=2)\n",
    "\n",
    "\n",
    "def add_table(filename, filters):\n",
    "    with tables.open_file(\n",
    "        \"{}-{}.h5\".format(filename, filters.complib), \"a\", filters=filters\n",
    "    ) as h5a:\n",
    "        pmt = h5a.create_table(h5a.root, \"pmt\", PMTRD)\n",
    "        pmtr = pmt.row\n",
    "        for i in range(NEVENTS):\n",
    "            for j in range(NPMTS):\n",
    "                pmtr[\"event_id\"] = i\n",
    "                pmtr[\"npmt\"] = j\n",
    "                pmtr.append()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 0 ns, sys: 0 ns, total: 0 ns\n",
      "Wall time: 1.79 ms\n"
     ]
    }
   ],
   "source": [
    "# Using no compression\n",
    "%time add_table(\"PMTAs\", tables.Filters(complib=\"zlib\", complevel=0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 173,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 0 ns, sys: 0 ns, total: 0 ns\n",
      "Wall time: 1.74 ms\n"
     ]
    }
   ],
   "source": [
    "# Using Zlib (level 5) compression\n",
    "%time add_table(\"PMTAs\", tables.Filters(complib=\"zlib\", complevel=5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 174,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 4 ms, sys: 0 ns, total: 4 ms\n",
      "Wall time: 1.52 ms\n"
     ]
    }
   ],
   "source": [
    "# Using Blosc (level 9) compression\n",
    "%time add_table(\"PMTAs\", tables.Filters(complib=\"blosc:lz4\", complevel=9))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 175,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.0M PMTAs-blosc:lz4.h5  4.1M PMTAs-zlib.h5\t   550M PMTs-None-0.h5\r\n",
      "550M PMTAs-None.h5\t  42M PMTs-blosc:lz4-9.h5   17M PMTs-zlib-5.h5\r\n"
     ]
    }
   ],
   "source": [
    "!ls -sh *.h5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "After adding the table we continue to see that a better compression ratio is achieved for EArray + Table with respect to a single Table.  Also, Blosc can make writing files significantly faster than not using compression (it has to write less)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Retrieving data from a single Table"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 187,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def read_single_table(complib, complevel):\n",
    "    with tables.open_file(\n",
    "        \"PMTs-{}-{}.h5\".format(complib, complevel), \"r\"\n",
    "    ) as h5t:\n",
    "        pmt = h5t.root.pmt\n",
    "        for i, row in enumerate(pmt):\n",
    "            event_id, npmt, pmtrd = (\n",
    "                row[\"event_id\"],\n",
    "                row[\"npmt\"],\n",
    "                row[\"pmtrd\"][:],\n",
    "            )\n",
    "            if i % 20 == 0:\n",
    "                print(event_id, npmt, pmtrd[0:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(1, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(3, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(5, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(6, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(8, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "CPU times: user 24 ms, sys: 80 ms, total: 104 ms\n",
      "Wall time: 99 ms\n"
     ]
    }
   ],
   "source": [
    "%time read_single_table(\"None\", 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 178,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(1, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(3, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(5, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(6, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(8, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "CPU times: user 576 ms, sys: 24 ms, total: 600 ms\n",
      "Wall time: 593 ms\n"
     ]
    }
   ],
   "source": [
    "%time read_single_table(\"zlib\", 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(1, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(3, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(5, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(6, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(8, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "CPU times: user 776 ms, sys: 16 ms, total: 792 ms\n",
      "Wall time: 782 ms\n"
     ]
    }
   ],
   "source": [
    "%time read_single_table(\"blosc:lz4\", 9)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As Blosc could not compress the table, it has a performance that is worse (quite worse actually) to the uncompressed table.  On its hand, Zlib can be more than 3x slower for reading than without compression."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Retrieving data from the EArray + Table"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 180,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def read_earray_table(complib, complevel):\n",
    "    with tables.open_file(\"PMTAs-{}.h5\".format(complib, \"r\")) as h5a:\n",
    "        pmt = h5a.root.pmt\n",
    "        pmtrd_ = h5a.root.pmtrd\n",
    "        for i, row in enumerate(pmt):\n",
    "            event_id, npmt = row[\"event_id\"], row[\"npmt\"]\n",
    "            pmtrd = pmtrd_[event_id, npmt]\n",
    "            if i % 20 == 0:\n",
    "                print(event_id, npmt, pmtrd[0:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(1, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(3, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(5, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(6, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(8, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "CPU times: user 4 ms, sys: 80 ms, total: 84 ms\n",
      "Wall time: 82 ms\n"
     ]
    }
   ],
   "source": [
    "%time read_earray_table(\"None\", 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 182,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(1, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(3, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(5, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(6, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(8, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "CPU times: user 992 ms, sys: 104 ms, total: 1.1 s\n",
      "Wall time: 1.09 s\n"
     ]
    }
   ],
   "source": [
    "%time read_earray_table(\"zlib\", 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 183,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(1, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(3, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(5, 0, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(6, 8, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "(8, 4, array([606530, 606530, 606530, 606530, 606530], dtype=int32))\n",
      "CPU times: user 168 ms, sys: 4 ms, total: 172 ms\n",
      "Wall time: 171 ms\n"
     ]
    }
   ],
   "source": [
    "%time read_earray_table(\"blosc:lz4\", 9)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So, the EArray + Table takes a similar time to read than a pure Table approach when no compression is used. And for some reason, when Zlib is used for compressing the data, the EArray + Table scenario degrades read speed significantly.  However, when the Blosc compression is used, the EArray + Table works actually faster than for the single Table. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Some plots on speeds and sizes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 184,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's have a look at the speeds at which data can be stored and read using the different paradigms:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 188,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n+b322qt6fbfddmPNmjUALF26lJ49e1Yfy16vaeHChQwfPpzS0lJKS0spKytDEu+8806T43/sscc4\n8sgjKSsro0uXLsyYMYPly5dXH+/atSvt27ev3q6oqGDp0qV1xjR69OjqmLp06cLy5cubFZNZoXPy\nNmtF+vbtyyWXXMLcuXObfG63bt22Gv29rWvYPXv2ZMyYMVRVVVFVVcXKlStZs2YNRx11VJNe86OP\nPuK8885jxIgRLF++nJUrV1JZWbnVdfHly5ezfv36reLq3r17nTF9//vfrxXToEGDmhSTWRo4eZul\n2Jtvvsmdd95Z3bpcvHgxkydP5uijj25yXeeddx533303S5cuZdWqVdx+++31lv3mN7/J6NGjee21\n1wD48MMPtzmQbIuag9U+/vhjNm7cSNeuXYFMK3zmzJlblVm/fj233norGzZs4Nlnn+Xpp5/mnHPO\nqVX35Zdfzj333FPdTb5mzRoef/xxPvnkkwbjMksb3ypm1kwVe+3VqNu5tqf+hhQXF/P8889z5513\n8uGHH9K5c2cGDhxYb+KtOQAte/sb3/gGb731FocccgidOnVi2LBhPPfccxQVFdUqO2jQINauXcv5\n55/PokWL6NSpEyeddFKdSXVbr19WVsYPf/hDzjjjDDZu3MjZZ5/N6aefvlWZffbZh7Zt21JeXk6n\nTp34+c9/TkVFRa36Pv/5z/PjH/+YK664gvnz57P77rtz3HHHcfLJJ28zJrM08pSgOdSrVzmLF+fu\nj3tL69lzLxYtei/fYRSknXFayCeffJIrr7ySt99+O9+h5NXO+Lu3wlHflKBueefQ4sXLmDEj31E0\nXmVler5oWMv75JNPmDFjBieffDLvvfceo0aN4ktf+lK+wzKzOviat5kBmevRI0aMoLS0lMMOO4yD\nDjqIUaNG5TssM6uDW95mBsCuu+7KCy+8kO8wzKwRnLzNzGynkLZxSNvi5G1mZjuFtI1DAqisrHu/\nr3mbmZmljJO3mZlZyjh5m5mZpYyTt5ml3uDBgxk9enSdx9atW0dRUVGdk5mYpVVOk7ekHpKelfQ3\nSX+VNKyecj+W9JakOZL65TIms5bSq1c5knK29OpV3uhYevfuzW677UZJSQnFxcWUlJQwbNi//rvN\nnDmToqIi7rjjjlz8KLbblVdeWR13hw4daN++PSUlJZSUlNR6XGpz1DcvuVla5Xq0+UbgOxExR1JH\n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\nwoS6y+2IbnMlS10eAy4CkHQUsCoilu2AmMzMzFIrpy1vSQ+Q6d0uk7QIGEFmcpOIiLER8YSkL0r6\nO5lbxb6Wy3jMzMxag5wm74gY0ogyQxsqY2ZmZv+S79HmZmZm1kT5HrBmZmYp1Lu8nIXLPEQpX5y8\nzcysyRYuW0bkO4gmqm/kdBq529zMzCxlnLzNzMxSxsnbzMwsZZy8zczMUsbJ28zMLGWcvM3MzFLG\nydvMzCxlnLzNzMxSxsnbzMwsZZy8zczMUsbJ28zMLGWcvM3MzFLGydvMzCxlnLzNzMxSxsnbzMws\nZZy8zczMUsbJ28zMLGWcvM3MzFLGydvMzCxlnLzNzMxSxsnbzMwsZZy8zczMUsbJ28zMLGVynrwl\nnSrpDUnzJF1Xx/GLJb0v6eVkuTTXMZmZmaVZ21xWLqkI+G/gBGAp8KKkqRHxRo2iv4qIYbmMxczM\nrLXIdcv7COCtiFgYERuAXwFn1VFOOY7DzMys1ch18t4bWJy1vSTZV9OXJM2R9KCkHjmOyczMLNVy\n2m3eSI8BD0TEBkmXAxPIdLPXMjJrvX+ymJmZtRZz5mSWhuQ6eb8D9Mra7pHsqxYRK7M2fwbcXl9l\nI1syMjMzswLTr19m2WLChLrL5brb/EVgP0kVktoD55NpaVeTVJ61eRbwWo5jMjMzS7WctrwjYpOk\nocBTZL4o3B8Rr0saBbwYEb8Fhkk6E9gAVAGX5DImMzOztMv5Ne+IeBL4VI19I7LWbwRuzHUcZmZm\nrYWfsGZmZpYyTt5mZmYp4+RtZmaWMk7eZmZmKePkbWZmljJO3mZmZinj5G1mZpYyTt5mZmYp4+Rt\nZmaWMk7eZmZmKePkbWZmljJO3mZmZinj5G1mZpYyTt5mZmYp4+RtZmaWMk7eZmZmKePkbWbb1KtX\nOZJStfTqVZ7vH5tZTrXNdwBmVtgWL17GjBn5jqJpKiuX5TsEs5xy8jbbwXqXl7NwmZOLmTWfk7fZ\nDrZw2TIi30E0gfIdgJnV4mveZmZmKePkbWZmljJO3mZmZinj5G1mZpYyTt5mZmYp4+RtZmaWMk7e\nZmZmKZPz5C3pVElvSJon6bo6jreX9CtJb0n6X0m9ch2TmZlZmuU0eUsqAv4bOAU4CBgs6dM1il0G\nVEXE/sBdwO25jMnMzCztct3yPgJ4KyIWRsQG4FfAWTXKnAVMSNanACfkOCYzM7NUy3Xy3htYnLW9\n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\nczOz7TF48GBGjx5d57F169ZRVFRU52QmZmnl5G3WTL16lSMpZ0uvXuWNjqV3797stttulJSUUFxc\nTElJCcOGDas+PnPmTIqKirjjjjty8aPYbldeeWV13B06dKB9+/aUlJRQUlJS63GpzVHfvORmaVUw\n3eZmabN48bKc3k1QWdn456ZLYtq0aVRWVtZ5fOLEiZSVlTFx4kSuvfbaeuvZtGkTbdq0aXBfcy1c\nuJD+/fvXeuTqfffdx3333QfAqFGjmD9/PhMnTmyR1wTfRWGtj1veZq1EfQnqo48+YsqUKdx77728\n9dZbvPzyy9XHFi5cSFFREePGjaOiooITTjihzn2QmXWsW7dudOnShf79+1fPKPbSSy9RXl6+1es/\n8sgj9OvXr854mtMK3rRpE+eccw7l5eWUlpZywgknMG/evK3KvPfeewwYMICSkhJOOumkervJP/nk\nE66++mp69epF9+7dGT58OBs2bGhyTGb55ORt1so9/PDDFBcXc+6553LyySczYcKEWmV+//vf88Yb\nbzB9+vR6933xi19k/vz5vP/++xx66KF89atfBeDwww9njz324Kmnnqo+d9KkSVxyySUt+j4GDRrE\n22+/zXvvvcenP/1pLr744q2OT5o0idtuu43ly5ez33771Tq+xbe//W2WLl3K3/72N958803mzZvH\nbbfd1qKxmuWak7dZKzFo0CBKS0vp0qULpaWl3H///UCmy/z8889HEkOGDOFXv/oVmzZtqj5PEqNG\njWLXXXelQ4cO9e675JJL2G233WjXrh233HILr7zyCqtXrwbgoosu4he/+AUAVVVVTJ8+ncGDB9eK\nsbnd123atOGCCy5g1113pX379tx88828+OKLrF+/fqv3f8QRR9C+fXtGjx7NM888w4oVK7aqZ9Om\nTYwbN467776b4uJiiouLue6665g8eXKz4jLLl1Ql71wODsrFYrYjTZ06laqqKlauXElVVRWXXXYZ\nS5YsYcaMGQwZMgSAM888k48//php06ZtdW6PHj1q1Ze9b/PmzVx//fXst99+dO7cmX322QdJLF++\nHIALLriA3/72t3z88cc8+OCDHHfcceyVzEc+efLk6i8Un/nMZ1i0aNFWXzKWLFnS4HvbtGkT11xz\nDX369KFz584ccMABRMRWyblnz57V6126dKFjx461us6XLl3Khg0bOOiggygtLaW0tJRBgwZVvw+z\n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\n8i91O5CzigAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f57fd0d0250>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=False, sharey=False)\n",
    "fig.set_size_inches(w=8, h=7, forward=False)\n",
    "f = 0.550  # conversion factor to GB/s\n",
    "rects1 = ax1.bar(\n",
    "    np.arange(3), f / np.array([0.323, 3.17, 0.599]), 0.25, color=\"r\"\n",
    ")\n",
    "rects2 = ax1.bar(\n",
    "    np.arange(3) + 0.25, f / np.array([0.250, 2.74, 0.258]), 0.25, color=\"y\"\n",
    ")\n",
    "_ = ax1.set_ylabel(\"GB/s\")\n",
    "_ = ax1.set_xticks(np.arange(3) + 0.25)\n",
    "_ = ax1.set_xticklabels((\"No Compr\", \"Zlib\", \"Blosc\"))\n",
    "_ = ax1.legend((rects1[0], rects2[0]), (\"Single Table\", \"EArray+Table\"), loc=9)\n",
    "_ = ax1.set_title(\"Speed to store data\")\n",
    "\n",
    "rects1 = ax2.bar(\n",
    "    np.arange(3), f / np.array([0.099, 0.592, 0.782]), 0.25, color=\"r\"\n",
    ")\n",
    "rects2 = ax2.bar(\n",
    "    np.arange(3) + 0.25, f / np.array([0.082, 1.09, 0.171]), 0.25, color=\"y\"\n",
    ")\n",
    "_ = ax2.set_ylabel(\"GB/s\")\n",
    "_ = ax2.set_xticks(np.arange(3) + 0.25)\n",
    "_ = ax2.set_xticklabels((\"No Compr\", \"Zlib\", \"Blosc\"))\n",
    "_ = ax2.legend((rects1[0], rects2[0]), (\"Single Table\", \"EArray+Table\"), loc=9)\n",
    "_ = ax2.set_title(\"Speed to read data\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And now, see the different sizes for the final files:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 190,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nUTz//PPtqkkqG4Nc6iJGjhxJt27dGD9+PPfffz9LlixZp03z3u+9997LE088wfTp07ntttt44IEH\ngEqgTp06lWeeeYYnn3ySO++8s9We81133cWll17KnXfeyWuvvcZBBx3EuHHjNmofBg8ezNSpU/nr\nX//KNddcw1e/+tW1AnjWrFm8++67LFy4kOuuu47TTz+9xZvzPProo5x11llMnjyZxsZGTj31VMaO\nHdvqFxGpzAxyqYvo1asXjzzyCHV1dXzhC19g++2355hjjuG1115rdZkLLriAXr16MWTIEOrr63n6\n6acB+PnPf84555zDDjvsQJ8+fZgwYUKr67j22mu54IILGDlyJHV1dUyYMIGnn36auXPnbvA+HH30\n0QwdOhSAQw45hFGjRvHII4+smb/FFltw4YUX0r17dw499FAOO+ywFnvl1113HWeddRb77LMPEcHn\nPvc5VqxYseZ6AakrMcilLmS33XZj0qRJzJkzh2effZYFCxZw7rnnttp+4MCBa4a33nprli1bBsCC\nBQsYMmTImnnVw83Nnj2bc845h/79+9O/f38GDBhARDB//vwNrv/uu+/mYx/7GAMGDKBfv35MmzaN\nRYsWrZm/3Xbb0aNHjzXjw4YNY8GCBS3WNHHixDU19evXj0WLFm1UTdLmziCXuqiRI0cyfvx4nn32\n2Q1edocddljrKvK2znkPGTKEa6+9lsbGRhobG1m8eDHLli1j//3336Btvvnmm5x44olcdNFFLFq0\niMWLF1NfX7/WefRFixaxcuXKteoaPHhwizV9+9vfXqemsWPHblBNUhkY5FIXMWPGDH7wgx+s6XXO\nnTuXm2++mQMOOGCD13XiiSdyxRVXsGDBApYsWcJll13WatsvfelLTJw4keeeew6AN954o82L0Jo0\nv9Dtrbfe4t1332W77bYDKr3zhoaGtdqsXLmS73znO7zzzjs89NBDPPjggxx//PHrrPsLX/gCP/rR\nj9YcSl+2bBn33HMPb7/99nrrksrGn59JXUSvXr147LHH+MEPfsAbb7xB3759GTNmTKsh3Pziterx\nz3/+87z44ovstdde9OnTh7PPPpuHH36Yurq6ddqOHTuW5cuXc9JJJzFnzhz69OnDJz/5yRYDtq3t\nDxgwgO9///scffTRvPvuuxx77LEcddRRa7XZeeed6d69O4MGDaJPnz789Kc/ZdiwYeus78ADD+TK\nK6/ki1/8Ii+99BIf+MAHOPjggzn88MPbrEkqI59+Jm2glp6ANXzQIGa347feG2vYwIHMeuWVmq1/\nfe6//36+/OUv85e//KXTatgc+PQzdRaffibV2KxXXiEza/bq6BB/++23+fd//3dWrVrF/PnzueSS\nSzjuuOM6tAZJ7VPaHnln17ChttyyjrffLs9vWIcMGcicOZ3XA9ycvR96ZW+99RajRo1ixowZbLXV\nVhx99NFcfvnlbLPNNp1dWqd6P/zba/PUVo+8tEFetqoDmDats6tov/r6dS9GUoV/zN+//LdXZ/HQ\nuiRJXZRBLklSiRnkkiSVmEEuSVKJGeSSJJWYQS6pyxg3bhwTJ05scd6KFSuoq6tr8SErUpkZ5NIm\nMHToICKiZq+hQwe1q47hw4ez9dZb07t3b3r16kXv3r05++yz18xvaGigrq6O733ve7V6K/4mX/7y\nl9fU3bNnT3r06EHv3r3p3bv3Ordr3RitPVNdKjPvtS5tAnPnLqzpfQLq69t3+9eI4N5776W+vr7F\n+VOmTGHAgAFMmTKF8847r9X1rFq1im7duq132saaPXs2o0ePXueWr1dffTVXX301AJdccgkvvfQS\nU6ZM2STbBO+NoK7JHrnUxbQWVm+++Sa33347V111FS+++CJPPvnkmnmzZ8+mrq6OSZMmMWzYMA49\n9NAWp0HlyWg77LAD/fr1Y/To0WueevaHP/yBQYMGrbX9X/ziF+yzzz4t1rMxveNVq1Zx/PHHM2jQ\nIPr378+hhx7KzJkz12rzyiuvcMghh9C7d28++clPtnoo/e233+bcc89l6NChDB48mHPOOYd33nln\ng2uSOptBLr1P3HHHHfTq1YsTTjiBww8/nMmTJ6/T5je/+Q0vvPACU6dObXXakUceyUsvvcSrr77K\nRz/6UT7zmc8AsO+++7LtttvywAMPrFn2xhtvZPz48Zt0P8aOHctf/vIXXnnlFT70oQ9x+umnrzX/\nxhtv5NJLL2XRokXssssu68xv8rWvfY0FCxbwpz/9iRkzZjBz5kwuvfTSTVqr1BEMcqmLGTt2LP37\n96dfv37079+f66+/HqgcVj/ppJOICE4++WRuueUWVq1atWa5iOCSSy5hq622omfPnq1OGz9+PFtv\nvTVbbLEFF154IdOnT2fp0qUAnHbaafzsZz8DoLGxkalTpzJu3Lh1atzYQ9zdunXjlFNOYauttqJH\njx5861vf4vHHH2flypVr7f9+++1Hjx49mDhxIr/+9a95/fXX11rPqlWrmDRpEldccQW9evWiV69e\nnH/++dx8880bVZfUmQxyqYu56667aGxsZPHixTQ2NnLmmWcyb948pk2bxsknnwzApz/9ad566y3u\nvffetZbdaaed1llf9bTVq1czYcIEdtllF/r27cvOO+9MRLBo0SIATjnlFH71q1/x1ltvcdttt3Hw\nwQczcOBAAG6++eY1Xy723ntv5syZs9YXjnnz5q1331atWsU3vvENRowYQd++fdl9993JzLWCesiQ\nIWuG+/XrxzbbbLPO4fUFCxbwzjvv8OEPf5j+/fvTv39/xo4du2Y/pDIxyKUupqXe7pQpU8hMxowZ\nww477MCIESNYsWLFOofXWzpvXT3tpptu4p577uGhhx5iyZIlzJo1a82jVgEGDx7MAQccwB133MGN\nN97IqaeeumbZcePGrfly8cwzzzB06NC1vnC09CWiuRtuuIFf//rXPPzwwyxZsoQXXnhhnX2eO3fu\nmuHGxkaWL1/O4MGD11rPDjvswBZbbMFLL71EY2MjjY2NLFmyhFdffXW9NUibG4Nceh+YMmUKF198\nMU8//TTTp09n+vTp3H777dx7770sXrwYaPkLQPNpS5cupWfPnvTr14/ly5dzwQUXrBP+p556Kpdd\ndhnPPvtsm88w35jD60uXLmXLLbekX79+LFu2jH/8x39cp81dd93F448/zooVK/inf/on6uvrGTBg\nwFptunfvzhlnnMHZZ5+9pjc/d+5cHnzwwQ2uSepsBrnUxYwZM2at35EfcsghzJkzh6985Stsv/32\na15jxoxh1113XXNeeH29caicAx86dCg77rgje+65JwceeOA6yxx77LHMnj2b4447ji233LLVOjfm\nqvUzzzyTbbfdlkGDBrH33ntz8MEHr7POU045hfPPP5/tttuOGTNmrHXUoXqbl19+OYMHD2bfffel\nb9++ay7ik8rG55F3EJ9H3nW09EzqoUMHMXdu+37rvTGGDBnInDmv1Gz9m9ouu+zCddddxyGHHNLZ\npWxSPo9cnaWt55F7QxhpEyhTyNbaHXfcQV1dXZcLcWlzVfMgj4hZwBvAauCdzNwvIvoBtwLDgFnA\niZn5RtH+SuAIYDkwPjOfrnWNkjaN+vp6nn/+eW688cbOLkV63+iIHvlqYHRmLq6aNgF4MDMvi4jz\ngQuACRFxBDAiM3eNiI8B1wD7d0CNkjaBaWU6fyR1ER1xsVu0sJ1jgKYrUCYX403TpwBk5mNAn4gY\n2AE1SpJUSh0R5AlMjYjHI+JzxbSBmbkQIDNfAZrCekdgbtWy84tpkiSpBR1xaP3jmflyRGwHPBAR\nM6iEe7UNvgz04qrh0cVLkqSuoKGhgYaGhna1rXmQZ+bLxX9fi4g7gf2AhRExMDMXRsQgoOl2SvOB\nIVWL71RMW8fFtStZatOwYcN8rvX71LBhwzq7BL1PjB49mtGjR68Zv+SSS1ptW9Mgj4itgbrMXBYR\nHwAOBy4B7gbGA98t/ntXscjdwFeBWyNif2BJ0yF4aXMxa9aszi5BktaodY98IPDLiMhiW/+WmQ9E\nxB+A2yLiDGA2cCJAZt4XEUdGxJ+p/PzsszWuT5KkUvPObh3EO7tJkjZWW3d2817rkiSVmEEuSVKJ\nGeSSJJWYQS5JUokZ5JIklZhBLklSiRnkkiSVmEEuSVKJGeSSJJWYQS5JUokZ5JIklZhBLklSiRnk\nkiSVmEEuSVKJGeSSJJWYQS5JUokZ5JIklZhBLklSiRnkkiSVmEEuSVKJGeSSJJWYQS5JUokZ5JIk\nlZhBLklSiRnkkiSVmEEuSVKJGeSSJJWYQS5JUokZ5JIklZhBLklSiRnkkiSVmEEuSVKJGeSSJJWY\nQS5JUokZ5JIklZhBLklSiRnkkiSVWIcEeUTURcSTEXF3MT48Ih6NiJkRcXNEdC+m94iIWyLixYj4\nXUQM7Yj6JEkqq47qkZ8DPFc1/l3gXzJzJLAEOLOYfibQmJm7ApcDl3VQfZIklVLNgzwidgKOBP61\navIhwB3F8GRgbDF8TDEOcDtwaK3rkySpzDqiR/5D4DwgASJiALA4M1cX8+cBOxbDOwJzATJzFbAk\nIvp3QI2SJJVSTYM8Io4CFmbm00BUz2rvKjZ9VZIkdR3da7z+jwOfjogjga2AXsAVQJ+IqCt65TsB\n84v284EhwIKI6Ab0zszGllZ8cdXw6OIlSVJX0NDQQENDQ7vaRmbWtpqmDUWMAr6RmZ+OiFuBX2Tm\nrRFxNTA9M6+JiK8Ae2bmVyLiJGBsZp7Uwro6qOpNJ4Bp0zq7ivarr4eO+mxIktoWEWRmi0epO+t3\n5BOAr0fETKA/cH0x/Xpg24h4ETi3aCdJklrRYT3yTckeee3ZI5ekzcfm2COXJEmbgEEuSVKJGeSS\nJJWYQS5JUokZ5JIklZhBLklSiRnkkiSVmEEuSVKJGeSSJJWYQS5JUokZ5JIklZhBLklSiRnkkiSV\nmEEuSVKJGeSSJJWYQS5JUokZ5JIklZhBLklSiRnkkiSVmEEuSVKJGeSSJJWYQS5JUokZ5JIklZhB\nLklSiRnkkiSVmEEuSVKJGeSSJJWYQS5JUokZ5JIklZhBLklSiRnkkiSVmEEuSVKJGeSSJJWYQS5J\nUokZ5JIklZhBLklSiRnkkiSVWJtBHhFbRsTpEfHpqDg/In4VEVdExLYdVaQkSWrZ+nrkU4DDgTOA\nBmAo8GNgKfDT9a08InpGxGMR8VRE/DEiLiqmD4+IRyNiZkTcHBHdi+k9IuKWiHgxIn4XEUM3ftck\nSer6uq9n/h6ZuWcRtPMyc1Qx/f6ImL6+lWfmioioz8w3I6Ib8B8RcT/wdeBfMvPnEXE1cCZwbfHf\nxszcNSL+HrgMOGljd06SpK5ufT3ylQCZ+S6woNm8Ve3ZQGa+WQz2pPLFIYF64I5i+mRgbDF8TDEO\ncDtwaHu2IUnS+9X6euQ7RcSVQFQNU4zv2J4NREQd8AQwArgKeAlYkpmriybzqta1IzAXIDNXRcSS\niOifmY3t3SFJkt5P1hfk51UN/6HZvObjLSoC+yMR0Rv4JfCh9pdHtDbj4qrh0cVLkqSuoKGhgYaG\nhna1jcysbTXVG4v4FvAW8D+BQZm5OiL2By7KzCOK8+cXZeZjxTn1lzNz+xbW04FVbxoBTJvW2VW0\nX309dORnQ5LUuoggM1vs3LbZI4+Iu9uan5mfXs/y2wLvZOYbEbEV8EngUmAacAJwK3A6cFexyN3F\n+GPF/IfaWr8kSe936zu0fgCVc9Y3UwnXVg91t2IHYHJxnrwOuDUz74uI54FbIuI7wFPA9UX764Gf\nRcSLwOt4xbokSW1q89B6cXj7k8A4YC/gXuDmzPxTx5TXal2lO+jroXVJ0sZq69B6mz8/y8xVmXl/\nZp4O7A/8GWiIiLNqUKckSdpA6zu0TkT0BI6i0isfDlxJ5epzSZLUydZ3sdsUYE/gPuCSzHy2Q6qS\nJEntsr5z5KuB5cVodcMAMjN717C2VnmOvPY8Ry5Jm4+N/vlZZvqYU0mSNmMGtSRJJWaQS5JUYga5\nJEklZpBLklRiBrkkSSVmkEuSVGIGuSRJJWaQS5JUYga5JEklZpBLklRiBrkkSSVmkEuSVGIGuSRJ\nJWaQS5JUYga5JEklZpBLklRiBrkkSSVmkEuSVGIGuSRJJWaQS5JUYga5JEklZpBLklRiBrkkSSVm\nkEuSVGIGuSRJJWaQS5JUYga5JEklZpBLklRiBrkkSSVmkEuSVGIGuSRJJWaQS5JUYjUN8ojYKSIe\niog/RcQfI+LsYnq/iHggImZExNSI6FO1zJUR8WJEPB0R+9SyPkmSyq7WPfJ3ga9n5oeBA4CvRsSH\ngAnAg5m5G/AQcAFARBwBjMjMXYEvAtfUuD5JkkqtpkGema9k5tPF8DLgeWAn4BhgctFscjFO8d8p\nRfvHgD4RMbCWNUqSVGYddo48IoYD+wCPAgMzcyFUwh5oCusdgblVi80vpkmSpBZ0SJBHxDbA7cA5\nRc88mzVpPi5Jktqhe603EBHdqYT4zzLzrmLywogYmJkLI2IQ8GoxfT4wpGrxnYpp67i4anh08ZIk\nqStoaGigoaGhXW0js7ad4YiYAizKzK9XTfsu0JiZ342ICUDfzJwQEUcCX83MoyJif+DyzNy/hXXW\nuOpNL4Bp0zq7ivarr4dafzYkSe0TEWRmtDSvpj3yiPg48BngjxHxFJVD6P8AfBe4LSLOAGYDJwJk\n5n0RcWRE/BlYDny2lvVJklR2NQ3yzPwPoFsrsw9rZZmzaleRJEldi3d2kySpxAxySZJKzCCXJKnE\nDHJJkkrMIJckqcQMckmSSswglySpxAxySZJKzCCXJKnEDHJJkkrMIJckqcQMckmSSswglySpxAxy\nSZJKzCCXJKnEDHJJkkrMIJckqcQMckmSSswglySpxAxySZJKzCCXJKnEDHJJkkrMIJckqcQMckmS\nSswglySpxAxySZJKzCCXJKnEDHJJkkrMIJckqcQMckmSSswglySpxAxySZJKzCCXJKnEDHJJkkrM\nIJckqcQMckmSSswglySpxAxySZJKrKZBHhHXR8TCiHimalq/iHggImZExNSI6FM178qIeDEino6I\nfWpZmyRJXUGte+Q3AP+t2bQJwIOZuRvwEHABQEQcAYzIzF2BLwLX1Lg2SZJKr6ZBnpmPAIubTT4G\nmFwMTy7Gm6ZPKZZ7DOgTEQNrWZ8kSWXXGefIt8/MhQCZ+QrQFNY7AnOr2s0vpkmSpFZ07+wCgNyY\nhS6uGh5dvCRJ6goaGhpoaGhoV9vI3KgcbbeIGAbck5l7FePPA6Mzc2FEDAKmZebuEXFNMXxr0e4F\n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\nr0N8AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f57fce4a490>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax1 = plt.subplots()\n",
    "fig.set_size_inches(w=8, h=5)\n",
    "rects1 = ax1.bar(np.arange(3), np.array([550, 17, 42]), 0.25, color=\"r\")\n",
    "rects2 = ax1.bar(np.arange(3) + 0.25, np.array([550, 4.1, 9]), 0.25, color=\"y\")\n",
    "_ = ax1.set_ylabel(\"MB\")\n",
    "_ = ax1.set_xticks(np.arange(3) + 0.25)\n",
    "_ = ax1.set_xticklabels((\"No Compr\", \"Zlib\", \"Blosc\"))\n",
    "_ = ax1.legend((rects1[0], rects2[0]), (\"Single Table\", \"EArray+Table\"), loc=9)\n",
    "_ = ax1.set_title(\"Size for stored datasets\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The main conclusion here is that, whenever you have a lot of data to dump (typically in the form of an array), a combination of an EArray + Table is preferred instead of a single Table.  The reason for this is that HDF5 can store the former arrangement more efficiently, and that fast compressors like Blosc works way better too."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The deep explanation on why using an EArray to store the raw data gives these advanatges is because we are physically (not only logically!) separating data that is highly related (like the result of some measurements) and also is homogeneous (of type Int32 in this case).  This manual separation is critical for getting better compression ratios and faster speeds too, specially when using fast compressors like Blosc."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "Finally, although meaningful, this experiment is based on a pure synthetic dataset.  It is always wise to use your own data in order to get your conclusions.  It is specially recommended to have a look at the different compressors that comes with PyTables and see which one fits better to your needs: http://www.pytables.org/usersguide/libref/helper_classes.html"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
